import 'dart:async';
import 'dart:io';

import 'package:get/get.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:share_fit/app/controllers/base/base_controller.dart';
import 'package:share_fit/app/helper/ext/tr_ext.dart';
import 'package:share_fit/app/helper/upgrade_helper.dart';
import 'package:share_fit/app/tools/app_const.dart';
import 'package:share_fit/app/tools/color_const.dart';
import 'package:share_fit/app/tools/log_utils.dart';
import 'package:share_fit/app/ute/uteped_const.dart';
import 'package:share_fit/app/ute/uteped_device.dart';
import 'package:share_fit/generated/locales.g.dart';
import 'package:clipboard/clipboard.dart';

import 'device_state.dart';
import 'unbind/device_unbind_utils.dart';

class DeviceLogic extends BaseController implements DeviceChangeListener {
  UTEPedDevice utePedDevice = UTEPedDevice.instance;
  final DeviceState state = DeviceState();
  UpgradeHelper upgradeHelper = UpgradeHelper.instance;

  @override
  void onInit() {
    super.onInit();
    UTEPedDevice.instance.addListener(this);
    _addListeners();
    
    String address = read(UTEPedConst.keyAddress, global: true);
    if (address.isNotEmpty) {
      state.address.value = address;
      state.hasConnectedDevice.value = true;
    }

    String battery = read(UTEPedConst.keyBattery, global: true);
    if (battery.isNotEmpty) {
      state.battery.value = battery;
    }

  }

  void _addListeners() {
    addStorageListener(UTEPedConst.keyAddress, (value) {
      state.hasConnectedDevice.value = value.toString().isNotEmpty;
      _updateDeviceInfo();
    }, global: true);

    addStorageListener(UTEPedConst.keyBattery, (value) {
      state.battery.value = value;
      _updateDeviceInfo();
    }, global: true);

    addStorageListener(AppConst.tabPage, (value) {
      _onPageChanged(value);
    }, global: true);

    addStorageListener(UTEPedConst.keyUpgradable, (value) {
      if (value != null) {
        state.isUpgradable = value;
      }
      else {
        state.isUpgradable = false;
      }

      if (Get.currentRoute == "/device") {
        _checkShowUpgradeDialog();
      }
    }, global: false);
  }

  Future<void> unbindDevice(address) async {
    state.hasConnectedDevice.value = false;

    state.unbindAddress.value = address;
    state.name.value = "";
    utePedDevice.unbindDevice(address);

    // remove upgrade info
    remove(UTEPedConst.keyUpgradable);
    remove(UTEPedConst.keyUpgradeInfo);
    remove(UTEPedConst.keyUpgradeDialogShow);
  }

  @override
  Future<void> onReady() async {
    super.onReady();

    if (Platform.isAndroid) {
      var utePedConfig = UTEPedDevice.instance.getUteConfig();
      var isNotificationEnable = await utePedConfig.isNotificationEnable();
      if (!isNotificationEnable) {
        Get.defaultDialog(
            title: LocaleKeys.info.ts,
            textConfirm: LocaleKeys.ok.ts,
            textCancel: LocaleKeys.cancel.ts,
            buttonColor: ColorConst.accentColor,
            middleText: LocaleKeys.notificationEnableTips.ts,
            barrierDismissible: false,
            onConfirm: () => {
              Get.back(),
              utePedConfig.checkNotificationEnable()
            });
      }
    }
  }

  @override
  void onClose() {
    UTEPedDevice.instance.removeListener(this);
    super.onClose();
  }

  @override
  void onDeviceChangeEvent(event) {
    String address = event[UTEPedConst.keyAddress];
    String action = event[UTEPedConst.keyAction];
    if (action == UTEPedConst.actionDisconnect) {
      state.isConnected.value = false;

      if (state.unbindAddress.value.isNotEmpty && state.unbindAddress.value == address) {
        state.unbindAddress.value = "";
        _autoDismissUnbindSuccessDialog();
        DeviceUnbindUtils.showUnbindSuccessDialog();
      }
    }
    else if (action == UTEPedConst.actionConnect) {
      if (state.address.value == address) {
        state.isConnected.value = true;
        state.hasConnectedDevice.value = true;
      }
    }
    _updateDeviceInfo();
  }

  void _autoDismissUnbindSuccessDialog() {
    const timeout = Duration(seconds: 3);
    Timer(timeout, () {
      DeviceUnbindUtils.dismissUnbindSuccessDialog();
    });
  }

  @override
  String getRemotePath() {
    return UTEPedConst.pathDevice;
  }

  @override
  String getStoragePath() {
    return UTEPedConst.pathDevice;
  }

  @override
  void initState() {
    state.address.value = getAddress();
  }

  @override
  bool useMethodSupport() {
    return true;
  }

  @override
  List<String> getSupportedMethods() {
    return [UTEPedConst.methodLocalNotify];
  }

  @override
  void onRemoteEvent(event, method) {
    if (method == UTEPedConst.methodLocalNotify) {
      logger.d("on localNotify ${event[UTEPedConst.keyValue]}");
      switch(event[UTEPedConst.keyAction]) {
        case UTEPedConst.actionSyncDataComplete:
          _checkUpdate();
          break;

        case UTEPedConst.actionBluetoothStateOff:
        case UTEPedConst.actionBluetoothStateOn:
          _checkDeviceStatus();
          break;
      }
    }
    else if (method == UTEPedConst.methodConnect || method == UTEPedConst.methodDisconnect) {
      int status = event[UTEPedConst.keyStatus];
      String address = event[UTEPedConst.keyAddress];
      if (state.address.value == address) {
        if (status == UTEPedConst.stateDisconnected) {
          state.isConnected.value = false;
        }
        else if (status == UTEPedConst.stateConnected) {
          state.isConnected.value = true;
          _checkDeviceStatus();
        }
      }
    }
  }

  Future<void> _checkUpdate() async {
    await upgradeHelper.checkUpdate();
    _checkShowUpgradeDialog();
  }

  void _updateDeviceInfo() {
    if (state.name.value.isEmpty) {
      state.name.value = utePedDevice.deviceInfo.name;
    }
    state.address.value = utePedDevice.deviceInfo.address??"";
    state.battery.value = utePedDevice.battery;
    logger.d("_updateDeviceInfo: ${state.name.value}");
    refreshDeviceIcon();
  }

  void _onPageChanged(value) {
    if (value == AppConst.devicePage) {
      logger.d("device page show...");
      UTEPedDevice.instance.isBluetoothEnable().then((value) => {
        if (!value) {
          // bluetooth not enabled
        }
      });
      _checkDeviceStatus();
      // utePedDevice.checkOnlineDevices();
    }
  }

  Future<void> _checkDeviceStatus() async {
    logger.d("_checkDeviceStatus...");
    var connected = await UTEPedDevice.instance.isConnected();
    state.isConnected.value = connected;
    if (!connected) {
      UTEPedDevice.instance.manualConnect();
    }
    else {
      if (!state.hasConnectedDevice.value) {
        state.hasConnectedDevice.value = true;
      }
      if (state.name.isEmpty || state.address.value.isEmpty || state.battery.value.isEmpty) {
        UTEPedDevice.instance.updateDeviceInfo().then((value) => {
          _updateDeviceInfo(),
          refreshDeviceIcon(),
        });
      }
      else {
        refreshDeviceIcon();
      }
      upgradeHelper.checkUpdateWithTime();
    }
  }

  void onDeviceInfoTap() {
    utePedDevice.isConnected().then((value) => {
      if (value) {
        Get.toNamed("device/unbind")
      }
    });
  }

  void onDeviceInfoDoubleTap() {
    FlutterClipboard.copy('${state.name.value}\n${state.address.value}');
  }

  void refreshDeviceIcon() {
    logger.d("getDeviceIcon: ${state.name.value}");
    String icon = 'assets/images/device/watch_default.png';
    if (state.name.value.startsWith("MEGA")) {
      icon = 'assets/images/device/watch_MEGA.png';
    }
    if (state.name.value.startsWith("Callie")) {
      icon = 'assets/images/device/watch_Callie.png';
    }
    if (state.name.value.startsWith("Helio")) {
      icon = 'assets/images/device/watch_Helio.png';
    }
    if (state.name.value.startsWith("Vibe")) {
      icon = 'assets/images/device/watch_Vibe_Fit.png';
    }

    state.deviceIcon = icon;

    update(['deviceIcon']);
  }

  Future<void> onItemTaped(route) async {
    if (route.contains("permission")) {
      Get.toNamed(route);
    }
    else if (route.contains("scan")) {
      _checkToScanPage(route);
    }
    else if (route.contains("search")) {
      await _checkToSearchPage(route);
    }
    else {
      var connected = await UTEPedDevice.instance.isConnected();
      if (connected) {
        var result = await Get.toNamed(route);
        if (route.contains("upgrade")) {
          update(["upgradeItem"]);
        }
        else if (route.contains("reset")) {
          connected = await UTEPedDevice.instance.isConnected();
          if (!connected && result) {
            delayed(()=> UTEPedDevice.instance.manualConnect(), milliseconds: 3000);
          }
        }
      }
      else {
        showTips(LocaleKeys.info.ts, LocaleKeys.device_not_connected.ts);
      }
    }
  }

  Future<void> _checkToScanPage(route) async {

    var btEnabled = await UTEPedDevice.instance.isBluetoothEnable();
    if (!btEnabled) {
      _showBtDisableDialog();
      return;
    }

    var granted = await Permission.camera.isGranted;
    if (!granted) {
      granted = await Permission.camera.request().isGranted;
      if(!granted){
        showPermissionDialog(LocaleKeys.camera_permission_tips.ts);
        return;
      }
    }

    granted = await Permission.location.isGranted;
    if (!granted) {
      granted = await Permission.location.request().isGranted;
      if(!granted){
        showPermissionDialog(LocaleKeys.location_permission_tips.ts);
        return;
      }
    }

    await Get.toNamed(route);
    _checkDeviceStatus();
  }

  Future<void> _checkToSearchPage(route) async {
    var btEnabled = await UTEPedDevice.instance.isBluetoothEnable();
    if (!btEnabled) {
      _showBtDisableDialog();
      return;
    }
    var granted = false;
    if (Platform.isAndroid) {
      granted = await Permission.bluetoothScan.isGranted;
      if (!granted) {
        granted = await Permission.bluetoothScan.request().isGranted;
        if(!granted){
          showPermissionDialog(LocaleKeys.bluetooth_permission_tips.ts);
          return;
        }
      }
    }
    else {
      granted = await Permission.bluetooth.isGranted;
      if (!granted) {
        granted = await Permission.bluetooth.request().isGranted;
        if(!granted){
          showPermissionDialog(LocaleKeys.bluetooth_permission_tips.ts);
          return;
        }
      }
    }

    granted = await Permission.location.isGranted;
    if (!granted) {
      granted = await Permission.location.request().isGranted;
      if(!granted){
        showPermissionDialog(LocaleKeys.location_permission_tips.ts);
        return;
      }
    }

    if (Platform.isAndroid) {
      granted = await Permission.locationWhenInUse.isGranted;
      if (!granted) {
        granted = await Permission.locationWhenInUse.request().isGranted;
        if(!granted){
          showPermissionDialog(LocaleKeys.location_permission_tips.ts);
        }
      }
    }

    await Get.toNamed(route);
    _checkDeviceStatus();
  }

  void _showBtDisableDialog() {
    Get.defaultDialog(
        title: LocaleKeys.info.ts,
        textConfirm: LocaleKeys.open.ts,
        textCancel: LocaleKeys.cancel.ts,
        buttonColor: ColorConst.accentColor,
        middleText: LocaleKeys.device_search_tips.ts,
        barrierDismissible: false,
        onCancel: () => {},
        onConfirm: () =>
        {Get.back(), vRemoteReqAsync(UTEPedConst.methodTurnBluetooth, {UTEPedConst.keyEnable: true})});
  }

  Future<void> _checkShowUpgradeDialog() async {
    update(["upgradeItem"]);
    var showed = read(UTEPedConst.keyUpgradeDialogShow, defaultValue: false);
    var upgradable = read(UTEPedConst.keyUpgradable, defaultValue: false);
    var connected = await UTEPedDevice.instance.isConnected();
    if (!showed && connected && upgradable) {
      Get.defaultDialog(
          title: LocaleKeys.info.ts,
          textConfirm: LocaleKeys.upgrade.ts,
          textCancel: LocaleKeys.cancel.ts,
          buttonColor: ColorConst.accentColor,
          middleText: LocaleKeys.firmware_new_version.ts,
          barrierDismissible: false,
          onCancel: () => {
            save(UTEPedConst.keyUpgradeDialogShow, true)
          },
          onConfirm: () => {
            save(UTEPedConst.keyUpgradeDialogShow, true),
            Get.back(),
            Get.toNamed("/device/settings/upgrade")
          });
    }
  }
}
